-- $ find links/example/xyz -name "*.lua" -exec lua util/preload.lua links/example/ embed_xyz {} +

-- arg[1]: prefix ("links/example/" gets removed from package.preload key)
--         "links/example/xyz/foo.lua" is assigned to package.preload['xyz.foo']
-- arg[2]: embed_fnc_name (output is "embed_xyz.c", function is "int embed_xyz(L)"
-- arg[3...]: Lua files to compile and embed

assert(#arg >= 3)

local outhnd, err = io.open(arg[2] .. '.c', 'w+')
if outhnd then
  local function outf(fmt, ...)
    outhnd:write(string.format(fmt, ...))
  end
  local str, base
  local exp = '^' .. arg[1]:gsub('%p', '.') .. '(.-)%.lua$'
  outf('// Automatically generated by preload.lua\n\n')
  outf('#include <lua.h>\n')
  outf('#include <lauxlib.h>\n\n')
  outf('static int preload(lua_State *L, const unsigned char data[1], unsigned int len, const char * name) {\n')
  outf('  int rc;\n')
  outf('  rc = luaL_loadbuffer(L, (const char *) data, len, name);\n')
  outf('  if (LUA_OK == rc) lua_setfield(L, -2, name);\n')
  outf('  // If error occurred, it is on top of stack now\n')
  outf('  return rc;\n')
  outf('}\n\n')
  outf('int %s(lua_State *L) {\n', arg[2])
  outf('  int rc;\n\n')
  outf('  rc = LUA_OK;\n')
  outf('  // put package.preload on top of stack\n')
  outf('  // ...\n')
  outf('  lua_getglobal(L, "package");\n')
  outf('  // ... package\n')
  outf('  lua_getfield(L, -1, "preload");\n')
  outf('  // ... package preload\n')
  outf('  lua_remove(L, -2);\n')
  outf('  // ... preload\n')
  for j = 3, #arg do
    str, err = loadfile(arg[j])
    if str then
      base = arg[j]:gsub(exp, '%1'):gsub('%p', '.')
      str = string.dump(str)
      outf('  {\n')
      outf("    static const unsigned char A[] = {\n      ")
      local collen = 0
      for k = 1, #str do
        outf('%d,', string.byte(str, k, k))
        collen = collen + 1
        if collen >= 32 then
          outf('\n      ')
          collen = 0
        end
      end
      outf('    };\n')
      outf('    if (LUA_OK == rc) rc = preload(L, A, %u, "%s");\n', #str, base)
      outf('  }\n')
    end
  end
  outf('  if (LUA_OK == rc) lua_pop(L, 1); // pop preload unless error is on top of stack\n')
  outf('  return rc;\n')
  outf('}\n')
  outhnd:close()
end
